﻿using System;
using System.Windows.Browser;

namespace FirstFloor.P2P
{
    /// <summary>
    /// Provides interoperability with the Live Messenger P2P stack. This class is for internal use only.
    /// </summary>
    [Scriptable]
    public class P2PInterop
    {
        /// <summary>
        /// Occurs when the application closes the channel.
        /// </summary>
        [Scriptable]
        public event EventHandler<EventArgs> ChannelCloseApp;
        /// <summary>
        /// Occurs when the application enters an instant message.
        /// </summary>
        [Scriptable]
        public event EventHandler<ValueEventArgs> ChannelEnterIM;
        /// <summary>
        /// Occurs when the application sends data.
        /// </summary>
        [Scriptable]
        public event EventHandler<ValueEventArgs> ChannelSendData;
        /// <summary>
        /// Occurs when the application sends an instant message.
        /// </summary>
        [Scriptable]
        public event EventHandler<ValueEventArgs> ChannelSendIM;
        /// <summary>
        /// Occurs when the application sends an instant message as user.
        /// </summary>
        [Scriptable]
        public event EventHandler<ValueEventArgs> ChannelSendIMAsUser;
        /// <summary>
        /// Opens an url in a new window
        /// </summary>
        [Scriptable]
        public event EventHandler<ValueEventArgs> WindowOpen;

        private P2PApplication application;

        /// <summary>
        /// Initializes a new instance of the <see cref="P2PInterop"/> class.
        /// </summary>
        /// <param name="application">The application.</param>
        internal P2PInterop(P2PApplication application)
        {
            this.application = application;
        }

        private void ValidateState()
        {
            if (this.application.State != P2PApplicationState.RemoteAppLoaded) {
                throw new InvalidOperationException(string.Format("Invalid application state {0}", this.application.State));
            }
        }

        /// <summary>
        /// Sets the application state.
        /// </summary>
        /// <param name="state">The state.</param>
        [Scriptable]
        public void SetState(int state)
        {
            this.application.SetState((P2PApplicationState)state);
        }

        /// <summary>
        /// Raises a P2PException.
        /// </summary>
        /// <param name="nr">The nr.</param>
        /// <param name="message">The message.</param>
        [Scriptable]
        public void RaiseP2PException(int nr, string message)
        {
            throw new P2PInteropException(nr, message);
        }

        /// <summary>
        /// Adds a user.
        /// </summary>
        /// <param name="email">The email.</param>
        /// <param name="globalIp">The global ip.</param>
        /// <param name="localIp">The local ip.</param>
        /// <param name="name">The name.</param>
        /// <param name="puid">The puid.</param>
        /// <param name="isMe">if set to <c>true</c> is me.</param>
        /// <param name="isInviter">if set to <c>true</c> is inviter.</param>
        [Scriptable]
        public void AddUser(string email, string globalIp, string localIp, string name, string puid, bool isMe, bool isInviter)
        {
            this.application.Users.Add(email, globalIp, localIp, name, puid, isMe, isInviter);
        }

        /// <summary>
        /// Handles the OnAppClose channel event.
        /// </summary>
        [Scriptable]
        public void Channel_OnAppClose()
        {
            this.application.SetState(P2PApplicationState.Closed);
        }

        /// <summary>
        /// Handles the OnDataError channel event.
        /// </summary>
        /// <param name="type">The type.</param>
        /// <param name="data">The data.</param>
        [Scriptable]
        public void Channel_OnDataError(int type, string data)
        {
            if (this.application.State == P2PApplicationState.RemoteAppLoaded) {
                this.application.OnSendDataError(new P2PDataError(type, data));
            }
        }

        /// <summary>
        /// Handles the OnDataReceived channel event.
        /// </summary>
        /// <param name="data">The data.</param>
        [Scriptable]
        public void Channel_OnDataReceived(string data)
        {
            if (this.application.State == P2PApplicationState.RemoteAppLoaded) {
                this.application.OnDataReceived(data);
            }
        }

        /// <summary>
        /// Handles the OnIMReceived channel event.
        /// </summary>
        /// <param name="im">The im.</param>
        [Scriptable]
        public string Channel_OnIMReceived(string im)
        {
            if (this.application.State == P2PApplicationState.RemoteAppLoaded) {
                this.application.OnIMReceived(ref im);
                return im;
            }
            return im;
        }

        /// <summary>
        /// Handles the OnRemoteAppClosed channel event.
        /// </summary>
        [Scriptable]
        public void Channel_OnRemoteAppClosed()
        {
            this.application.SetState(P2PApplicationState.RemoteAppClosed);
        }

        /// <summary>
        /// Handles the OnRemoteAppLoaded channel event.
        /// </summary>
        [Scriptable]
        public void Channel_OnRemoteAppLoaded()
        {
            this.application.SetState(P2PApplicationState.RemoteAppLoaded);
        }

        /// <summary>
        /// Handles the OnTypeChanged channel event.
        /// </summary>
        /// <param name="type">The type.</param>
        [Scriptable]
        public void Channel_OnTypeChanged(int type)
        {
            this.application.OnConnectionTypeChanged((P2PConnectionType)type);
        }

        /// <summary>
        /// Closes the application.
        /// </summary>
        internal void CloseApp()
        {
            if (this.application.State != P2PApplicationState.ErrorNotHostedInLiveMessenger) {
                if (ChannelCloseApp != null) {
                    ChannelCloseApp(this, EventArgs.Empty);
                }
            }
        }

        /// <summary>
        /// Enters an instant message.
        /// </summary>
        /// <param name="im">The im.</param>
        internal void EnterIM(string im)
        {
            ValidateState();
            if (ChannelEnterIM != null) {
                ChannelEnterIM(this, new ValueEventArgs(im));
            }
        }

        /// <summary>
        /// Sends data to the remote party.
        /// </summary>
        /// <param name="data">The data.</param>
        internal void SendData(string data)
        {
            ValidateState();
            if (ChannelSendData != null) {
                ChannelSendData(this, new ValueEventArgs(data));
            }
        }

        /// <summary>
        /// Sends an instant message.
        /// </summary>
        /// <param name="im">The im.</param>
        internal void SendIM(string im)
        {
            ValidateState();
            if (ChannelSendIM != null) {
                ChannelSendIM(this, new ValueEventArgs(im));
            }
        }

        /// <summary>
        /// Sends an instant message that appears to come from the user.
        /// </summary>
        /// <param name="im">The im.</param>
        internal void SendIMAsUser(string im)
        {
            ValidateState();
            if (ChannelSendIMAsUser != null) {
                ChannelSendIMAsUser(this, new ValueEventArgs(im));
            }
        }

        /// <summary>
        /// Opens specified url in a new window
        /// </summary>
        /// <param name="url">The URL.</param>
        internal void OpenWindow(string url)
        {
            if (WindowOpen != null) {
                WindowOpen(this, new ValueEventArgs(url));
            }
        }
    }
}
